<template>
  <!-- 图片查看器模态框 -->
  <div v-if="showImageViewer" class="image-viewer-modal" @click.self="closeImageViewer">
    <div class="image-viewer-container">
      <button class="viewer-close" @click="closeImageViewer">×</button>
      <button class="viewer-nav viewer-nav-left" @click="prevImage" :disabled="currentImageIndex === 0">‹</button>
      <div class="image-viewer-content" @wheel.prevent="handleWheel" @mousedown="handleMouseDown" @mousemove="handleMouseMove" @mouseup="handleMouseUp" @mouseleave="handleMouseUp">
        <img 
          ref="viewerImage"
          :src="panels[currentImageIndex]?.image" 
          :style="imageViewerStyle"
          @dragstart.prevent
        />
      </div>
      <button class="viewer-nav viewer-nav-right" @click="nextImage" :disabled="currentImageIndex === panels.length - 1">›</button>
      <div class="viewer-info">分镜 {{ currentImageIndex + 1 }} / {{ panels.length }}</div>
    </div>
  </div>

  <section class="card">
    <h2>📄 输入小说文本</h2>
    <p class="muted">粘贴或输入您的小说内容，我们将为您生成分镜草案</p>
    <textarea v-model="text" placeholder="在此粘贴文本…"></textarea>
    <div class="controls-row">
      <div class="control-group">
        <label class="muted">分镜数量：</label>
        <input type="number" v-model.number="targetPanelCount" min="1" max="20" class="number-input" />
      </div>
      <button class="btn" @click="loadExample">示例小说</button>
      <button class="btn" @click="analyze">分析</button>
      <span class="muted">{{ hint }}</span>
    </div>
  </section>

  <section v-if="panels.length > 0" class="card" style="margin-bottom:12px">
    <div class="style-controls">
      <div class="style-selector">
        <label class="muted">预设风格：</label>
        <select v-model="style" class="style-select">
          <option>日式漫画</option>
          <option>美式漫画</option>
          <option>卡通风格</option>
          <option>写实风格</option>
        </select>
      </div>
      <button class="btn" @click="generateAll">生成所有图片</button>
      <span class="muted">{{ generateHint }}</span>
    </div>
  </section>

  <section v-if="panels.length > 0" class="card">
    <h2>🎬 分镜配置与预览</h2>
    <div class="panel-list">
      <div v-for="(panel, idx) in panels" :key="panel.id" class="panel-card">
        <div class="panel-header">
          <h3>分镜 #{{ idx + 1 }}</h3>
          <button class="btn-delete" @click="deletePanel(idx)">删除</button>
        </div>
          <div class="panel-content">
            <div class="panel-image">
              <img 
                v-if="panel.image" 
                :src="panel.image" 
                alt="分镜预览" 
                class="comic-preview"
                @click="openImageViewer(idx)"
                style="cursor: pointer;"
              />
              <div v-else class="no-image">暂无图片</div>
            </div>
          <div class="panel-config">
            <div class="config-field">
              <label class="field-label">画面描述：</label>
              <textarea v-model="panel.imageDescription" placeholder="详细的画面描述（场景、镜头、人物等）" class="field-textarea"></textarea>
            </div>
            <div class="config-row">
              <div class="config-field">
                <label class="field-label">构图：</label>
                <input type="text" v-model="panel.shot" placeholder="如：close_up/medium/wide" class="field-input" />
              </div>
              <div class="config-field">
                <label class="field-label">角度：</label>
                <input type="text" v-model="panel.angle" placeholder="如：eye_level/high/low" class="field-input" />
              </div>
            </div>
            <div class="config-field">
              <label class="field-label">台词内容：</label>
              <input type="text" v-model="panel.dialogue" placeholder="角色台词" class="field-input" />
            </div>
            <div class="config-field">
              <label class="field-label">出场人物：</label>
              <input type="text" v-model="panel.characters" placeholder="如：女性角色（少女，遮住半边脸，侧身站在光线褪尽的傍晚）" class="field-input" />
            </div>
            <div class="config-actions">
              <button class="btn-small" @click="generateImage(idx)">生成图片</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>
</template>

<script setup>
import axios from 'axios';
import { ref, computed } from 'vue';
import { useStore } from '../stores/useStore';

const store = useStore();
const text = ref('');
const hint = ref('待分析');
const generateHint = ref('待生成');
const style = ref(store.stylePreset);
const targetPanelCount = ref(store.global.targetPanelCount || 3);
const panels = computed(() => store.panels);

// 图片查看器状态
const showImageViewer = ref(false);
const currentImageIndex = ref(0);
const scale = ref(1);
const offset = ref({ x: 0, y: 0 });
const isDragging = ref(false);
const dragStart = ref({ x: 0, y: 0 });

// 图片查看器样式
const imageViewerStyle = computed(() => ({
  transform: `scale(${scale.value}) translate(${offset.value.x}px, ${offset.value.y}px)`,
  transition: isDragging.value ? 'none' : 'transform 0.1s ease-out'
}));

function openImageViewer(idx) {
  currentImageIndex.value = idx;
  scale.value = 1;
  offset.value = { x: 0, y: 0 };
  showImageViewer.value = true;
}

function closeImageViewer() {
  showImageViewer.value = false;
  scale.value = 1;
  offset.value = { x: 0, y: 0 };
}

function nextImage() {
  if (currentImageIndex.value < panels.value.length - 1) {
    currentImageIndex.value++;
    scale.value = 1;
    offset.value = { x: 0, y: 0 };
  }
}

function prevImage() {
  if (currentImageIndex.value > 0) {
    currentImageIndex.value--;
    scale.value = 1;
    offset.value = { x: 0, y: 0 };
  }
}

function handleWheel(e) {
  const delta = e.deltaY;
  if (delta < 0) {
    scale.value = Math.min(scale.value * 1.1, 5);
  } else {
    scale.value = Math.max(scale.value / 1.1, 0.3);
  }
}

function handleMouseDown(e) {
  if (scale.value > 1) {
    isDragging.value = true;
    dragStart.value = {
      x: e.clientX,
      y: e.clientY
    };
  }
}

function handleMouseMove(e) {
  if (isDragging.value) {
    const deltaX = e.clientX - dragStart.value.x;
    const deltaY = e.clientY - dragStart.value.y;
    offset.value = {
      x: offset.value.x + deltaX,
      y: offset.value.y + deltaY
    };
    dragStart.value = {
      x: e.clientX,
      y: e.clientY
    };
  }
}

function handleMouseUp() {
  isDragging.value = false;
}

// 解析 characters 字符串为后端需要的数组格式
function parseCharacters(characterStr, defaultCharacters = []) {
  if (!characterStr) return defaultCharacters;
  
  // 尝试从字符串解析，例如："女性角色（少女）（沉思，遮住半边脸，侧身站在光线褪尽的傍晚）"
  // 支持中文括号和英文括号，支持复杂描述
  const match = characterStr.match(/^(.+?)[（(]([^）)]+)[）)][（(]([^）)]+)[）)]$/);
  if (match) {
    return [{
      name: match[1].trim(),
      emotion: match[2].trim(), // 情绪
      appearance: match[3].trim() // 外貌和动作描述
    }];
  }
  
  // 简化格式："角色名（情绪，动作描述）"
  const simpleMatch = characterStr.match(/^(.+?)[（(]([^）)]+)[）)]$/);
  if (simpleMatch) {
    const content = simpleMatch[2].trim();
    // 如果包含逗号，尝试分离情绪和动作
    if (content.includes('，') || content.includes(',')) {
      const parts = content.split(/[，,]/);
      return [{
        name: simpleMatch[1].trim(),
        emotion: parts[0].trim(),
        appearance: parts.slice(1).join('，').trim()
      }];
    } else {
      return [{
        name: simpleMatch[1].trim(),
        emotion: content,
        appearance: ''
      }];
    }
  }
  
  // 如果都不匹配，返回简单格式
  return [{
    name: characterStr.trim(),
    emotion: '',
    appearance: ''
  }];
}

function loadExample() {
  text.value = `风从海面卷起，咸湿的气息扑在她的肩头。
白衬衫的褶皱在风里翻起，如同想要挣脱某种无形的束缚。
她站在沙滩边，脚下的浪一遍遍抚摸又退去。
字幕在风声里闪烁：
"山的后面是什么？— What's beyond the mountain?"
她没回头，只是看着远方被雾吞噬的海平线。


她低头，
她侧身站在光线褪尽的傍晚，发丝被海风卷成几缕，
遮住半边脸，却藏不住她眼底的温柔。
字幕缓缓浮现：
"你不用告诉我 — You don't have to tell me —"
她轻轻一笑，那是决心也是告别。


镜头推近。她的脸只占画面的左半。
风穿过她的发间，带走最后一丝犹豫。
海浪在远处拍打，天地间只剩风声与呼吸。
她抬眼，目光越过山、越过海、越过时间。
字幕如呢喃：
"我会自己去看 — I will go see for myself —"

这一刻，整个世界都被风与光揉成了一帧旧底片。
她终于明白，答案不在山后，而在路上。`;
}

async function analyze(){
  hint.value = '分析中…';
  try{
    const { data } = await axios.post(store.baseUrl + '/api/analyze', { 
      text: text.value, 
      targetPanelCount: targetPanelCount.value 
    });
    const panelsData = (data.data.panels || []).map(p => {
      // 提取对话文本（包含说话者）
      const dialogueText = (p.dialog || []).map(d => {
        const speaker = d.speaker || '';
        const text = d.text || '';
        return speaker ? `${speaker}：${text}` : text;
      }).join('，');
      // 提取人物名称和情绪
      const characterNames = (p.characters || []).map(c => `${c.name}${c.emotion ? '(' + c.emotion + ')' : ''}`).join('、');
      // 生成图片描述
      const imageDescription = `${p.setting || ''}${p.shot ? '，' + p.shot + '镜头' : ''}${p.angle ? '，' + p.angle + '角度' : ''}`;
      // 生成展示词
      const displayWords = [p.setting, p.shot, p.angle, characterNames, dialogueText].filter(Boolean).join('，');
      
      return {
        ...p,
        // 保持原始字段
        sourceParagraphIds: p.sourceParagraphIds || [],
        shot: p.shot || '',
        angle: p.angle || '',
        setting: p.setting || '',
        charactersRaw: p.characters || [], // 保存原始数组格式
        dialog: p.dialog || [],
        // 添加界面显示用的字段
        imageSize: p.imageSize || '大图',
        dialogue: dialogueText,
        scene: p.setting || '',
        content: dialogueText,
        imageDescription: imageDescription,
        displayWords: displayWords,
        // 用于显示的字段
        characters: characterNames, // 转换为字符串用于显示
        characterList: (p.characters || []).map(c => c.name) // 人物列表
      };
    });
    store.setPanels(panelsData, { targetPanelCount: targetPanelCount.value });
    hint.value = data.mock ? '完成（MOCK）' : '完成';
  }catch(e){ 
    hint.value = '失败：' + (e?.message || ''); 
  }
}

function deletePanel(idx){
  if(confirm('确定要删除这个分镜吗？')){
    const newPanels = panels.value.filter((_, i) => i !== idx);
    store.setPanels(newPanels, store.global);
  }
}

async function generateImage(idx){
  generateHint.value = '生成图片中…';
  try{
    const panel = panels.value[idx];
    
    // 解析用户修改后的 characters 字符串为数组格式
    const characters = parseCharacters(panel.characters, panel.charactersRaw || []);
    
    // 构建后端需要的原始格式
    const backendPanel = {
      id: panel.id,
      sourceParagraphIds: panel.sourceParagraphIds,
      shot: panel.shot,
      angle: panel.angle,
      setting: panel.setting || panel.scene,
      characters: characters, // 使用解析后的数组
      dialog: panel.dialog || []
    };
    
    // 发送单个分镜的生成请求
    const { data } = await axios.post(store.baseUrl + '/api/generate', { 
      stylePreset: style.value, 
      panels: [backendPanel]
    });
    
    if(data?.data?.images && data.data.images.length > 0){
      // 更新当前分镜的图片
      panel.image = data.data.images[0].url;
      generateHint.value = data.mock ? '完成（MOCK）' : '完成';
    } else {
      generateHint.value = '生成失败';
    }
  }catch(e){ 
    generateHint.value = '失败：' + (e?.message||''); 
  }
}

function generateWords(idx){
  generateHint.value = '生成展示词中…';
  // TODO: 实现展示词生成
  setTimeout(() => generateHint.value = '展示词生成完成', 1000);
}

function addCharacter(idx){
  const name = prompt('请输入角色名称：');
  if(name && name.trim()){
    const panel = panels.value[idx];
    if(!panel.characterList) panel.characterList = [];
    panel.characterList.push(name.trim());
  }
}

async function generateAll(){
  generateHint.value = '生成中…';
  try{
    // 构建后端需要的格式
    const backendPanels = store.panels.map(panel => ({
      id: panel.id,
      sourceParagraphIds: panel.sourceParagraphIds,
      shot: panel.shot,
      angle: panel.angle,
      setting: panel.setting || panel.scene,
      characters: parseCharacters(panel.characters, panel.charactersRaw || []), // 使用解析后的数组
      dialog: panel.dialog || []
    }));
    
    // 一次性发送所有面板给后端，让后端并行处理
    const { data } = await axios.post(store.baseUrl + '/api/generate', { 
      stylePreset: style.value, 
      panels: backendPanels
    });
    
    if (data?.data?.images && data.data.images.length > 0) {
      // 更新每个分镜的图片
      data.data.images.forEach((img, idx) => {
        if (store.panels[idx]) {
          store.panels[idx].image = img.url;
        }
      });
      store.setImages(data.data.images);
      generateHint.value = '完成';
    } else {
      generateHint.value = '生成失败';
    }
  }catch(e){ 
    generateHint.value = '失败：' + (e?.message||''); 
  }
}
</script>

<style scoped>
.card{border:1px solid #e6e6eb;border-radius:20px;padding:14px;background:#fff;margin-bottom:12px;box-shadow:0 12px 30px rgba(45,17,83,.06)}
.row{display:flex;gap:10px;align-items:center;margin-top:8px}
.controls-row{display:flex;gap:10px;align-items:center;margin-top:8px;flex-wrap:wrap}
.control-group{display:flex;gap:5px;align-items:center}
.muted{color:#6e6e73;font-size:12px}
textarea{width:100%;min-height:220px;border:1px solid #e6e6eb;border-radius:14px;padding:10px;resize:vertical;font-family:inherit}
pre{white-space:pre-wrap}

.number-input{width:80px;padding:6px 10px;border:1px solid #e6e6eb;border-radius:10px;font-size:14px}
.btn{background:#7c3aed;color:#fff;border:0;padding:8px 12px;border-radius:10px;cursor:pointer;font-size:14px}
.btn:hover{background:#6d28d9}
.btn-large{padding:10px 20px;font-size:16px}
.btn-small{background:#7c3aed;color:#fff;border:0;padding:5px 10px;border-radius:8px;cursor:pointer;font-size:12px}
.btn-delete{background:#ef4444;color:#fff;border:0;padding:5px 10px;border-radius:8px;cursor:pointer;font-size:12px}
.btn-add-char{background:#10b981;color:#fff;border:0;padding:4px 8px;border-radius:6px;cursor:pointer;font-size:11px}

.panel-list{display:flex;flex-direction:column;gap:16px}
.panel-card{border:1px solid #e6e6eb;border-radius:12px;padding:14px;background:#fafafa}
.panel-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.panel-header h3{margin:0;font-size:16px;color:#1f1f1f}
.panel-content{display:flex;gap:16px}
.panel-image{flex:0 0 280px}
.comic-preview{width:100%;height:300px;object-fit:contain;border:1px solid #e6e6eb;border-radius:8px;background:#fff}
.no-image{width:100%;height:300px;border:1px solid #e6e6eb;border-radius:8px;background:#f5f5f5;display:flex;align-items:center;justify-content:center;color:#999;font-size:14px}
.panel-config{flex:1;display:flex;flex-direction:column;gap:8px}
.config-field{display:flex;flex-direction:column;gap:4px}
.config-row{display:flex;gap:12px}
.config-row .config-field{flex:1}
.field-label{font-size:13px;color:#6e6e73;font-weight:500}
.field-input,.field-textarea{width:100%;padding:6px 10px;border:1px solid #e6e6eb;border-radius:8px;font-size:13px;font-family:inherit}
.field-textarea{min-height:60px;resize:vertical}
.config-actions{display:flex;gap:8px;margin-top:4px}
.characters-section{margin-top:8px}
.character-list{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}
.character-badge{background:#e0e7ff;color:#4f46e5;padding:4px 10px;border-radius:12px;font-size:12px}

.style-controls{display:flex;align-items:center;gap:12px;padding:8px 0}
.style-selector{display:flex;align-items:center;gap:6px}
.style-select{padding:6px 10px;border:1px solid #e6e6eb;border-radius:10px;background:#fff;font-size:14px}

/* 图片查看器样式 */
.image-viewer-modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  cursor: grab;
}

.image-viewer-container {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.viewer-close {
  position: absolute;
  top: 20px;
  right: 20px;
  background: rgba(255, 255, 255, 0.2);
  border: none;
  color: white;
  font-size: 36px;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  cursor: pointer;
  z-index: 1001;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s;
}

.viewer-close:hover {
  background: rgba(255, 255, 255, 0.3);
}

.viewer-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(255, 255, 255, 0.2);
  border: none;
  color: white;
  font-size: 48px;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  cursor: pointer;
  z-index: 1001;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s;
}

.viewer-nav:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.3);
}

.viewer-nav:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.viewer-nav-left {
  left: 20px;
}

.viewer-nav-right {
  right: 20px;
}

.image-viewer-content {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  user-select: none;
}

.image-viewer-content img {
  max-width: 90%;
  max-height: 90%;
  object-fit: contain;
  cursor: move;
}

.image-viewer-content:active {
  cursor: grabbing;
}

.viewer-info {
  position: absolute;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.5);
  color: white;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 14px;
  z-index: 1001;
}
</style>
